package com.intelligent.security;

import com.intelligent.utils.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.regex.Pattern;

public class AuthInterceptor implements HandlerInterceptor {
    private static final Logger log = LoggerFactory.getLogger(AuthInterceptor.class);
    private static final Pattern JWT_PATTERN = Pattern.compile("^[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]+$");

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        // Allowlist internal or public endpoints (e.g., Feign, health checks)
        String uri = request.getRequestURI();
        if (uri.startsWith("/feign/") || uri.startsWith("/actuator") || uri.startsWith("/health")
                || uri.startsWith("/error")) {
            return true;
        }
        String token = extractToken(request);
        if (token == null) {
            if (log.isWarnEnabled()) {
                String auth = request.getHeader("Authorization");
                String xt = request.getHeader("X-Token");
                log.warn("[AUTHN] Missing token. method={}, uri={}, Authorization={}, X-Token={}",
                        request.getMethod(), request.getRequestURI(),
                        auth == null ? "<null>" : (auth.length() > 32 ? auth.substring(0, 32) + "..." : auth),
                        xt == null ? "<null>" : xt);
            }
            return unauthorized(response, "未提供令牌");
        }
        if (!JwtUtil.validate(token)) {
            log.warn("[AUTHN] Invalid/expired token. method={}, uri={}", request.getMethod(), request.getRequestURI());
            return unauthorized(response, "令牌无效或已过期");
        }
        Long userId = JwtUtil.getUserId(token);
        if (userId == null) {
            log.warn("[AUTHN] Cannot parse userId from token. method={}, uri={}", request.getMethod(),
                    request.getRequestURI());
            return unauthorized(response, "无法解析用户信息");
        }
        String userAccount = JwtUtil.getUserAccount(token);
        request.setAttribute("CURRENT_USER_ID", userId);
        request.setAttribute("CURRENT_USER_ACCOUNT", userAccount);
        // 设置请求头供其他组件使用
        request.setAttribute("X-User-Id", String.valueOf(userId));
        if (userAccount != null) {
            request.setAttribute("X-User-Account", userAccount);
        }
        if (log.isDebugEnabled()) {
            log.debug("[AUTHN] OK userId={} method={} uri={}", userId, request.getMethod(), request.getRequestURI());
        }
        return true;
    }

    private String extractToken(HttpServletRequest request) {
        // 1) Authorization header: Bearer <token> (case-insensitive)
        String auth = request.getHeader("Authorization");
        if (auth != null) {
            String a = auth.trim();
            if (a.length() >= 7 && a.regionMatches(true, 0, "Bearer ", 0, 7)) {
                return a.substring(7).trim();
            }
            // 1b) If Authorization contains a raw JWT (no Bearer), accept it
            if (JWT_PATTERN.matcher(a).matches()) {
                return a;
            }
        }
        // 2) X-Token header
        String xtoken = request.getHeader("X-Token");
        if (xtoken != null && !xtoken.isEmpty()) {
            String t = xtoken.trim();
            if (!t.isEmpty())
                return t;
        }
        // 3) Cookie 'token'
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie c : cookies) {
                if ("token".equalsIgnoreCase(c.getName())) {
                    String t = c.getValue();
                    if (t != null && !t.trim().isEmpty())
                        return t.trim();
                }
            }
        }
        // 4) Query param ?token=
        String qp = request.getParameter("token");
        if (qp != null && !qp.isEmpty())
            return qp.trim();
        return null;
    }

    private boolean unauthorized(HttpServletResponse response, String msg) throws IOException {
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
        response.setContentType("application/json;charset=UTF-8");
        String body = Result.error(HttpStatus.UNAUTHORIZED.value(), msg).toString();
        response.getWriter().write(body);
        return false;
    }
}
